using System;
using Blackbird.Core.Entities.Sprites;

namespace Blackbird.Core.Base
{
    /// <summary>
    /// Handles frame advaces based 
    /// </summary>
    public class BaseMultiframe : BaseRenderable
    {
        //accumulates the amount of time that's passed between multiple updates
        private long _accumDelta;
        private int _currentFrameIndex;
        private Frameset _currentFrameset;
        private bool _finished;

        // Used to determine frame advances...It's the number of ticks that must pass before incrementing 1 frame. 
        private long _ticksPerFrame;

        public override Frame CurrentFrame
        {
            get { return _currentFrameset[_currentFrameIndex]; }
        }

        public bool Finished
        {
            get { return _finished; }
            protected set { _finished = value; }
        }

        public virtual Frameset CurrentFrameset
        {
            get { return _currentFrameset; }
        }

        public int CurrentFrameIndex
        {
            get { return _currentFrameIndex; }
            protected set { _currentFrameIndex = value; }
        }

        //Handles the frame advancement based on the amount of
        //time passed and FPS requested.
        private int GetFrameAdvance()
        {
            long advance = 0;
            if (_ticksPerFrame == 0)
                return (int) advance;
            if (_accumDelta > _ticksPerFrame)
            {
                advance += (_accumDelta/_ticksPerFrame);
                _accumDelta -= (_ticksPerFrame*advance);
            }
            return (int) advance;
        }

        public void Reset()
        {
            _currentFrameIndex = 0;
            _finished = false;
        }

        public void ModulateCurrentFrame()
        {
            // Modulation will make the new frameset pick up on the same from as
            // the previous, or, if the current frameset has fewer frames that the
            // current frame index, it will modulate to an appropriate value.
            if (_currentFrameset.Count == 1)
                _currentFrameIndex = 0;
            else if (_currentFrameIndex > (_currentFrameset.Count - 1))
                _currentFrameIndex = _currentFrameIndex%(_currentFrameset.Count - 1);
        }

        public override void Update(long delta)
        {
            base.Update(delta);

            //Update the current Frame
            _accumDelta += delta;
            if ((_ticksPerFrame == 0) || _currentFrameset.Count == 1)
                _currentFrameIndex = 0;
            else
            {
                _currentFrameIndex += GetFrameAdvance();
                if (_currentFrameIndex >= (_currentFrameset.Count - 1))
                {
                    if (_currentFrameset.Loop)
                        ModulateCurrentFrame();
                    else
                    {
                        _finished = true;
                        _currentFrameIndex = _currentFrameset.Count - 1;
                    }
                }
            }
        }

        protected void SetCurrentFrameset(Frameset fs)
        {
            _currentFrameset = fs;
            if (Math.Abs(fs.Fps - 0.0) > 0)
                _ticksPerFrame = 0;
            else
            {
                _ticksPerFrame = (long) ((10000000.0)/fs.Fps);
            }
            if (!_currentFrameset.Loop)
                ModulateCurrentFrame();
            else
            {
                _currentFrameIndex = 0;
                _finished = false;
            }
        }
    }
}